grammar ExprSyntax;

//options { tokenVocab=CommonLexer; }
import CommonLexer;

@header {
package com.xrui.myexprparser;
}




//expressionList
//    : expression (',' expression)*
//    ;
//
//funcCall
//    : funcName '(' expressionList? ')'
//    ;
//
//funcName:
//  ABS;

//literals
//  : literal (',' literal)*
//  ;

//expr:
//     fieldName  bop=('<=' | '>=' | '>' | '<') (fieldName | literal)
//   | fieldName  bop=('==' | '!=') (fieldName | literal)
//   | fieldName  NOT? IN '(' literals ')'
//   | expr bop='&&' expr
//   | expr bop='||' expr
//   | '(' expr ')'
//  ;


// Simplified approach for expression
expressions
    : expression (',' expression)*
    ;

queryexpression:
    expression
    ;

expression
    : notOperator=(NOT | '!') expression                            #notExpression
    | expression logicalOperator expression                         #logicalExpression
    | predicate IS NOT? testValue=(TRUE | FALSE )                   #isExpression
    | predicate                                                     #predicateExpression
    ;

predicate
    : predicate NOT? IN '('  expressions ')'                        #inPredicate
    | predicate IS nullNotnull                                      #isNullPredicate
    | left=predicate comparisonOperator right=predicate             #binaryComparisonPredicate
    | predicate NOT? BETWEEN predicate AND predicate                #betweenPredicate
//    | predicate SOUNDS LIKE predicate                               #soundsLikePredicate
    | predicate NOT? LIKE predicate (STRING_LITERAL)?               #likePredicate
    | predicate NOT? regex=(REGEXP | RLIKE) predicate               #regexpPredicate
    | expressionAtom                                                #expressionAtomPredicate
    ;

expressionAtom
    : constant                                                      #constantExpressionAtom
    | fieldName                                                     #fullColumnNameExpressionAtom
//    | functionCall                                                  #functionCallExpressionAtom
    | unaryOperator expressionAtom                                  #unaryExpressionAtom
//    | BINARY expressionAtom                                         #binaryExpressionAtom
    | '(' expression (',' expression)* ')'                          #nestedExpressionAtom
//    | ROW '(' expression (',' expression)+ ')'                      #nestedRowExpressionAtom
    | EXISTS '(' expression ')'                                      #existsExpressionAtom
 //   | '(' selectStatement ')'                                       #subqueryExpressionAtom
 //   | INTERVAL expression intervalType                              #intervalExpressionAtom
    | left=expressionAtom bitOperator right=expressionAtom          #bitExpressionAtom
    | left=expressionAtom mathOperator right=expressionAtom         #mathExpressionAtom
 //   | left=expressionAtom jsonOperator right=expressionAtom         #jsonExpressionAtom
    ;


fieldName
    : ID (DOT ID)*
    ;

literal
    : integerLiteral
    | floatLiteral
    | CHAR_LITERAL
    | STRING_LITERAL
    | BOOL_LITERAL
    | NULL_LITERAL
    ;

integerLiteral
    : DECIMAL_LITERAL
    | HEX_LITERAL
    | OCT_LITERAL
    | BINARY_LITERAL
    ;

floatLiteral
    : FLOAT_LITERAL
    | HEX_FLOAT_LITERAL
    ;

constant
    : literal
    | NOT? nullLiteral=NULL_LITERAL
    ;
unaryOperator
    : '!' | '~' | '+' | '-' | NOT
    ;

bitOperator
    : '<' '<' | '>' '>' | '&' | '^' | '|'
    ;

mathOperator
    : '*' | '/' | '%' | DIV | MOD | '+' | '-' | '--'
    ;


logicalOperator
    : AND |   XOR | OR
    ;

comparisonOperator
    :  '>' | '<' | '<=' | '>='
    |'==' |  '!='
    ;

nullNotnull
    : NOT? (NULL_LITERAL )
    ;

orderByClause
    : orderByExpression (',' orderByExpression)*
    ;

orderByExpression
    : expression order=(ASC | DESC)?
    ;